package com.yb.framework.security.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.yb.framework.core.exception.BaseException;
import com.yb.module.system.domain.SysUser;
import com.yb.module.system.service.SysUserService;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
	
	@Autowired
	private SysUserService sysUserService;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// TODO Auto-generated method stub
		/**
		 * 这里为什么不抛UsernameNotFoundException？？？
		 * SpringSecurity会去捕获UsernameNotFoundException这个类型，
		 * 并抛出新的BadCredentialsException异常覆盖，导致异常信息仍是Bad Credential。
		 * 解决方案：使用BadCredentialsException或者自定义异常抛出，都OK。
		 * 参考：https://www.jianshu.com/p/b0cc88574f5d
		 */
		SysUser sysUser = sysUserService.getByUsername(username);
		if(sysUser == null) {
			throw new BadCredentialsException("用户[" + username + "]，不存在");
		} else if(sysUser.getStatus() != null && sysUser.getStatus() == 1) {
			throw new BaseException("用户[" + username + "]，已停用");
		}
		
		/**
		 * .roles()和.authorities()同时使用时，后者指定的权限（或角色）会覆盖掉前面的角色（或权限）。
		 * 原因：基于角色，还是基于权限，最后鉴权都落实到hasAnyAuthorityName方法，为了避免混合鉴权。
		 * 参考：https://blog.csdn.net/k0101jcj/article/details/104033741
		 * 
		 */
		// 添加角色
		List<String> authorities = new ArrayList<String>();
		for (String role : sysUserService.getRolesByUsername(username)) {
			authorities.add("ROLE_" + role);
		}
		// 添加权限
		if("root".equals(username) || "admin".equals(username)) {
			authorities.addAll(sysUserService.getALlPermissions());
		} else {
			authorities.addAll(sysUserService.getPermissionsByUsername(username));
		}
		
		return User.withUsername(username)
			.password(sysUserService.getByUsername(username).getPassword())
			.authorities(authorities.toArray(new String[(authorities.size())]))
			.disabled(false)       //账号失效
			.accountLocked(false)  //账号锁定
			.accountExpired(false) //账号过期
			.build();
	}
}
